#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
AI视频监控系统 - 主应用程序
使用Flask提供简单的Web界面
"""

import os
import cv2
import time
import asyncio
import base64
import numpy as np
from flask import Flask, render_template, request, jsonify, url_for
from werkzeug.utils import secure_filename

# 导入我们自己的模块
from multi_modal_analyzer import MultiModalAnalyzer
from config import VideoConfig, ServerConfig

# 创建必要的目录
os.makedirs('uploads', exist_ok=True)
os.makedirs('video_warning', exist_ok=True)
os.makedirs('static', exist_ok=True)

# 初始化Flask应用
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024  # 限制上传文件大小为100MB
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True

# 支持的视频格式
ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov', 'mkv'}

# 初始化多模态分析器
analyzer = MultiModalAnalyzer()

def allowed_file(filename):
    """检查文件类型是否被允许"""
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def extract_frames(video_path, interval=VideoConfig.ANALYSIS_INTERVAL):
    """
    从视频中提取帧
    
    参数:
        video_path: 视频文件路径
        interval: 每隔多少秒提取一组帧
        
    返回:
        frames_list: 帧组列表，每组包含BUFFER_DURATION秒的帧
        timestamps_list: 每组帧的开始和结束时间戳
    """
    try:
        print(f"开始从视频中提取帧: {video_path}")
        
        # 检查文件是否存在
        if not os.path.exists(video_path):
            print(f"错误: 视频文件不存在: {video_path}")
            return [], [], 0
        
        # 检查文件大小
        file_size = os.path.getsize(video_path)
        if file_size == 0:
            print(f"错误: 视频文件大小为0: {video_path}")
            return [], [], 0
        
        print(f"视频文件大小: {file_size} 字节")
        
        # 打开视频文件
        cap = cv2.VideoCapture(video_path)
        
        # 检查视频是否成功打开
        if not cap.isOpened():
            print(f"错误: 无法打开视频: {video_path}")
            return [], [], 0
        
        # 获取视频的FPS和总帧数
        fps = int(cap.get(cv2.CAP_PROP_FPS))
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        duration = total_frames / fps if fps > 0 else 0
        
        print(f"视频信息: 宽度={width}, 高度={height}, FPS={fps}, 总帧数={total_frames}, 时长={duration:.2f}秒")
        
        # 检查视频参数是否有效
        if fps <= 0 or total_frames <= 0 or width <= 0 or height <= 0:
            print(f"错误: 视频参数无效: FPS={fps}, 总帧数={total_frames}, 宽度={width}, 高度={height}")
            cap.release()
            return [], [], 0
        
        # 计算需要提取的帧
        buffer_frames = int(fps * VideoConfig.BUFFER_DURATION)  # 每个缓冲区的帧数
        interval_frames = int(fps * interval)  # 每个间隔的帧数
        
        print(f"提取参数: 缓冲区时长={VideoConfig.BUFFER_DURATION}秒, 间隔时间={interval}秒")
        print(f"每个缓冲区帧数={buffer_frames}, 每个间隔帧数={interval_frames}")
        
        # 如果视频太短，无法提取完整的缓冲区
        if total_frames < buffer_frames:
            print(f"警告: 视频太短，无法提取完整的缓冲区。尝试使用所有可用帧。")
            buffer_frames = total_frames
        
        frames_list = []
        timestamps_list = []
        
        # 处理整个视频
        segments_count = 0
        for start_frame in range(0, total_frames, interval_frames):
            # 如果剩余帧数不足一个完整的缓冲区，则跳过
            if start_frame + buffer_frames > total_frames:
                print(f"到达视频结尾，剩余帧数不足一个完整的缓冲区")
                break
                
            # 设置视频位置到开始帧
            print(f"处理第 {segments_count+1} 段视频，从帧 {start_frame} 开始")
            ret = cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
            if not ret:
                print(f"警告: 无法设置视频位置到帧 {start_frame}")
            
            # 获取这段视频的时间戳
            start_time = start_frame / fps
            end_time = (start_frame + buffer_frames) / fps
            
            # 格式化时间戳
            def format_timestamp(seconds):
                hours = int(seconds // 3600)
                minutes = int((seconds % 3600) // 60)
                seconds = int(seconds % 60)
                return f"{hours:02d}-{minutes:02d}-{seconds:02d}"
            
            start_timestamp = format_timestamp(start_time)
            end_timestamp = format_timestamp(end_time)
            
            print(f"时间范围: {start_timestamp} - {end_timestamp}")
            
            # 收集这段视频的帧
            frames = []
            frames_read = 0
            for i in range(buffer_frames):
                ret, frame = cap.read()
                if not ret:
                    print(f"警告: 在读取第 {i+1}/{buffer_frames} 帧时遇到文件结尾")
                    break
                frames.append(frame)
                frames_read += 1
            
            print(f"成功读取 {frames_read}/{buffer_frames} 帧")
            
            if frames:
                frames_list.append(frames)
                timestamps_list.append([start_timestamp, end_timestamp])
                segments_count += 1
            else:
                print(f"警告: 没有从这段视频中提取到帧")
        
        # 释放视频资源
        cap.release()
        
        print(f"共提取了 {len(frames_list)} 段视频，每段包含帧数: {[len(frames) for frames in frames_list]}")
        
        if not frames_list:
            print("错误: 没有从视频中提取到帧")
            return [], [], fps
        
        return frames_list, timestamps_list, fps
        
    except Exception as e:
        print(f"从视频中提取帧时出错: {e}")
        import traceback
        traceback.print_exc()
        return [], [], 0

@app.route('/')
def index():
    """主页路由"""
    return render_template('index.html')

@app.route('/upload', methods=['POST'])
def upload_file():
    """处理视频上传"""
    # 检查是否有文件被上传
    if 'video' not in request.files:
        return jsonify({'error': 'No file part'}), 400
    
    file = request.files['video']
    
    # 检查文件名是否为空
    if file.filename == '':
        return jsonify({'error': 'No selected file'}), 400
    
    # 检查文件类型
    if not allowed_file(file.filename):
        return jsonify({'error': f'File type not allowed. Supported types: {", ".join(ALLOWED_EXTENSIONS)}'}), 400
    
    # 保存文件
    filename = secure_filename(file.filename)
    file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
    file.save(file_path)
    
    # 创建结果存储字典
    results = {'segments': []}
    
    # 异步处理函数
    async def process_video():
        print(f"开始处理视频文件: {file_path}")
        
        # 从视频中提取帧
        print("开始提取视频帧...")
        frames_list, timestamps_list, fps = extract_frames(file_path)
        print(f"提取了 {len(frames_list)} 组帧，FPS: {fps}")
        
        if not frames_list:
            print("警告: 没有提取到视频帧")
            results['error'] = "无法从视频中提取帧"
            return
        
        # 处理每组帧
        print("开始逐段分析视频内容...")
        for i, (frames, timestamps) in enumerate(zip(frames_list, timestamps_list)):
            print(f"分析第 {i+1} 段视频 (时间范围: {timestamps[0]} - {timestamps[1]})...")
            
            try:
                # 分析当前帧组
                result = await analyzer.analyze(frames, fps, timestamps)
                print(f"第 {i+1} 段视频分析结果: {result}")
                
                # 记录结果
                segment_info = {
                    'segment_id': i + 1,
                    'start_time': timestamps[0],
                    'end_time': timestamps[1],
                    'has_alert': 'alert' in result and result['alert'] != '无异常'
                }
                
                # 如果有警报，添加更多信息
                if segment_info['has_alert']:
                    print(f"检测到异常: {result['alert']}")
                    segment_info.update({
                        'alert': result['alert'],
                        'description': result['description'],
                        'video_file': result.get('video_file_name'),
                        'image_file': result.get('picture_file_name')
                    })
                else:
                    print("未检测到异常")
                
                results['segments'].append(segment_info)
                print(f"第 {i+1} 段视频分析完成")
            except Exception as e:
                print(f"分析第 {i+1} 段视频时出错: {e}")
                import traceback
                traceback.print_exc()
                results['segments'].append({
                    'segment_id': i + 1,
                    'start_time': timestamps[0],
                    'end_time': timestamps[1],
                    'error': str(e)
                })
            
        # 添加总体总结
        results['summary'] = "视频处理完成"
        results['filename'] = filename
    
    # 运行异步处理
    try:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(process_video())
    except Exception as e:
        print(f"处理视频时出错: {e}")
        results['error'] = str(e)
    finally:
        loop.close()
    
    return jsonify(results)

@app.route('/results')
def results():
    """显示分析结果"""
    # 在实际应用中，这里会从数据库或文件中加载保存的结果
    # 在这个简化版本中，我们直接返回结果模板，前端会通过API获取结果
    return render_template('results.html')

@app.route('/api/results')
def api_results():
    """API接口，返回最新的分析结果"""
    try:
        # 检查video_warning目录中的警告视频和图片
        warning_files = []
        if os.path.exists('video_warning'):
            for file in os.listdir('video_warning'):
                if file.startswith('warning_') and (file.endswith('.mp4') or file.endswith('.avi') or file.endswith('.jpg')):
                    warning_files.append(file)
        
        # 检查uploads目录中的视频文件
        video_files = []
        if os.path.exists('uploads'):
            for file in os.listdir('uploads'):
                if file.endswith(('.mp4', '.avi', '.mov', '.mkv')):
                    video_files.append(file)
        
        # 收集分析结果
        results = {
            'status': 'success',
            'message': '分析完成',
            'warning_files': warning_files,
            'video_files': video_files,
            'timestamp': time.strftime('%Y-%m-%d %H:%M:%S')
        }
        
        # 如果有警告文件，添加警告信息
        if warning_files:
            results['has_alerts'] = True
            results['alert_message'] = '检测到异常情况，请查看警告文件'
        else:
            results['has_alerts'] = False
            results['alert_message'] = '未检测到异常情况'
        
        return jsonify(results)
    except Exception as e:
        print(f"获取分析结果时出错: {e}")
        return jsonify({'error': str(e), 'status': 'error'}), 500

if __name__ == '__main__':
    # 运行Flask应用
    app.run(
        host=ServerConfig.HOST,
        port=ServerConfig.PORT,
        debug=True
    )
